﻿/*
 PennyAuctionTracker
 Copyright (C) 2011  Devin Bileck
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software Foundation;
 either version 2 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with this program;
 if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace PennyAuctionTracker
{
	/// <summary>
	/// The main form of the program.
	/// </summary>
	public partial class MainForm : Form
	{
		/// <summary>
		/// Stores details about the auction.
		/// </summary>
		private Auction auction;
		
		/// <summary>
		/// List view column sorter.
		/// </summary>
		private ListViewColumnSorter lvwColumnSorter;
		
		/// <summary>
		/// Stores an index value used to update the list view.
		/// </summary>
		private int listViewIndex;
		
		/// <summary>
		/// Delegate for worker threads to update the UI.
		/// </summary>
		private delegate void UpdateUIDelegate();
		
		/// <summary>
		/// Class constructor.
		/// </summary>
		public MainForm()
		{
			// The InitializeComponent() call is required for Windows Forms designer support
			InitializeComponent();
			
			// Attach the list view column sorter to bidders list
    		lvwColumnSorter = new ListViewColumnSorter();
    		biddersList.ListViewItemSorter = lvwColumnSorter;
    		
    		// Sort by the Bids column
	        lvwColumnSorter.SortColumn = 1;
	        lvwColumnSorter.Order = SortOrder.Descending;
		}
		
		#region Menu events
		
		/// <summary>
		/// Handles the Click event for the File > New menu item.
		/// </summary>
		/// <param name="sender">Represents the control that raised the event.</param>
		/// <param name="e">Contains additional information about the event that was raised.</param>
		private void fileNew(object sender, EventArgs e)
		{
			NewForm Form = new NewForm();
		   	if (Form.ShowDialog(this) == DialogResult.OK)
		   	{
		   		// Update the status label
		   		statusLabel.Text = "Loading Auction...";
		   		statusLabel.ForeColor = System.Drawing.Color.Black;
		   		
		   		// Clear the list views
		   		bidHistoryList.Items.Clear();
		   		biddersList.Items.Clear();
		   		
		   		// Allow the UI to update
		   		Application.DoEvents();
		   		
		   		// Stop and disable the timer
		   		auctionRefreshTimer.Stop();
		   		auctionRefreshTimer.Enabled = false;

		   		// Create a new auction
		   		if (Form.AuctionSite.Text.Equals("QuiBids"))
		   		{
		   			auction = new QuiBids(Form.AuctionID.Text);
		   		}
		   		
		   		// Check if the auction is not valid
		   		if (!auction.isValid)
		   		{
		   			// Update the status label
		   			statusLabel.Text = "No Auction";
		   			
		   			// Inform the user
		   			MessageBox.Show("That is not a valid auction.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
		   		}
		   		else
		   		{
			   		// Start the timer to refresh the auction
			   		auctionRefreshTimer.Enabled = true;
			   		auctionRefreshTimer.Start();
			   		
			   		// Initialize the list view index
			   		this.listViewIndex = 0;
		   		}
		   	}
		   	Form.Dispose();
		}
		
		/// <summary>
		/// Handles the Click event for the File > Exit menu item.
		/// </summary>
		/// <param name="sender">Represents the control that raised the event.</param>
		/// <param name="e">Contains additional information about the event that was raised.</param>
		private void fileExit(object sender, EventArgs e)
		{
			// Exit the application
			Application.Exit();
		}
		
		/// <summary>
		/// Handles the Click event for the Help > About menu item.
		/// </summary>
		/// <param name="sender">Represents the control that raised the event.</param>
		/// <param name="e">Contains additional information about the event that was raised.</param>
		private void helpAbout(object sender, EventArgs e)
		{
			// Show the about form
			AboutForm Form  = new AboutForm();
			Form.ShowDialog(this);
			Form.Dispose();
		}
		
		#endregion
		
		#region UI events
		
		/// <summary>
		/// Handles the Click event for the bidders list columns.
		/// </summary>
		/// <param name="sender">Represents the control that raised the event.</param>
		/// <param name="e">Contains additional information about the event that was raised.</param>
		private void BiddersListColumnClick(object sender, ColumnClickEventArgs e)
		{
			// Determine if clicked column is already the column that is being sorted
		    if (e.Column == lvwColumnSorter.SortColumn)
		    {
		        // Reverse the current sort direction for this column
		        if (lvwColumnSorter.Order == SortOrder.Ascending)
		        {
		            lvwColumnSorter.Order = SortOrder.Descending;
		        }
		        else
		        {
		            lvwColumnSorter.Order = SortOrder.Ascending;
		        }
		    }
		    else
		    {
		        // Set the column that is to be sorted
		        lvwColumnSorter.SortColumn = e.Column;
		        lvwColumnSorter.Order = SortOrder.Ascending;
		    }
		    
		    // Sort the list
		    biddersList.Sort();
		}
		
		/// <summary>
		/// Updates the UI.
		/// </summary>
		private void UpdateUI()
		{
			// Check if this was called by a worker thread
			if (this.InvokeRequired)
		    {
		        // Marshal the call to the user interface thread
		        this.Invoke(new UpdateUIDelegate(UpdateUI));
		        return;
		    }
		    
		    // Update the status label text
			if (auction.TimeRemaining > 0)
			{
				TimeSpan t = TimeSpan.FromSeconds(auction.TimeRemaining);
				statusLabel.Text = "Time Remaining: " + String.Format("{0:D2}:{1:D2}:{2:D2}", t.Hours, t.Minutes, t.Seconds);
			}
			else
			{
				statusLabel.Text = "Auction Ended";
			}
			
			// Update the status label color
			if (auction.TimeRemaining > 30)
			{
				statusLabel.ForeColor = System.Drawing.Color.Black;
			}
			else
			{
				statusLabel.ForeColor = System.Drawing.Color.Red;
			}
			
			// Update the bid history list view
			for (int i = this.listViewIndex; i < auction.BidHistory.Count; i++)
			{
				Auction.Bid bid = (Auction.Bid)auction.BidHistory[i];
				if (!bidHistoryList.Items.ContainsKey(bid.Price))
				{
					String[] items = new String[] { bid.Price, bid.Bidder, bid.Type };
					ListViewItem list = new ListViewItem(items);
					list.Name = bid.Price;
					bidHistoryList.Items.Insert(0, list);
				}
				this.listViewIndex++;
			}
			
			// Update the bidders list view
			foreach (Auction.Bidder bidder in auction.Bidders)
			{
				// If the bidder isn't in the list
				if (!biddersList.Items.ContainsKey(bidder.Name))
				{
					// Add the bidder to the list
					String[] items = new String[] { bidder.Name, bidder.Bids.ToString(), String.Format("{0:C}", (bidder.Bids * 0.60)) };
					ListViewItem list = new ListViewItem(items);
					list.Name = bidder.Name;
					biddersList.Items.Add(list);
				}
				
				// If the bidder is already in the list
				else
				{
					// Update the bidders values
					ListViewItem[] list = biddersList.Items.Find(bidder.Name, false);
					list[0].SubItems[1].Text = bidder.Bids.ToString();
					list[0].SubItems[2].Text = String.Format("{0:C}", (bidder.Bids * 0.60));
				}
			}
			biddersList.Sort();
		}
		
		#endregion
		
		#region Timers and background workers
		
		/// <summary>
		/// Handles the Tick event for the auction refresh timer.
		/// </summary>
		/// <param name="sender">Represents the control that raised the event.</param>
		/// <param name="e">Contains additional information about the event that was raised.</param>
		private void auctionRefreshTimerTick(object sender, EventArgs e)
		{
			// Start the auction refresh worker thread if it isn't busy
			if (!auctionRefreshWorker.IsBusy)
			{
				auctionRefreshWorker.RunWorkerAsync();
			}
		}
		
		/// <summary>
		/// Handles the DoWork event for the auction refresh worker thread.
		/// </summary>
		/// <param name="sender">Represents the control that raised the event.</param>
		/// <param name="e">Contains additional information about the event that was raised.</param>
		private void AuctionRefreshWorkerDoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
		{
			// Update the auction
			auction.Update();
			
			// Update the UI
			UpdateUI();
			
			// Stop and disable the timer if the auction has finished
			if (auction.TimeRemaining == 0)
			{
				auctionRefreshTimer.Stop();
				auctionRefreshTimer.Enabled = false;
			}
		}
		
		#endregion
	}
}